using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels.Ipc;
using MSRI.HelperClasses;
using MSRI.SmsSessions;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Threading;

namespace MSRI.SmsService
{
    public delegate void OnMessageReceivedDelegate(string message);
    public delegate void OnConnectedDelegate(string name);
    public delegate void OnSendMessageDelegate(string ClientName, string Message);
    public delegate void OnSendSmsDelegate(string ClientName, SmsClass SmsMessage);
    public delegate SmsResponseClass OnSmsReceivedDelegate(SmsClass SmsMessage);
    public delegate void OnDeliveryReportDelegate(DeliveryReportClass DeliveryReport);
    public delegate bool IsClientConnectedDelegate();

    public class SmsPublishClass : MarshalByRefObject
    {
        private static string _ServerName = null;
        public static bool _IsConnected = false;
        public event OnSendMessageDelegate OnClientSendMessage;
        public event OnSendSmsDelegate OnClientSendSms;
        public event OnConnectedDelegate OnClientConnected;
        public event OnConnectedDelegate OnClientDisconnected;
        public static List<ClientClass> _ClientList = new List<ClientClass>();


        public bool IsConnected
        {
            get { return _IsConnected; }
            set { _IsConnected = value; }
        }
        public SmsPublishClass()
        {
        }


        public string ServerName
        {
            get { return _ServerName; }
        }
        public void Client2Server_SendMessage(string ClientName, string Message)
        {
            if ((OnClientSendMessage != null) &&
                 (OnClientSendMessage.GetInvocationList().Length > 0))
                OnClientSendMessage(ClientName, Message);
        }
        public void Client2Server_SendSms(string ClientName, SmsClass Message)
        {
            if ((OnClientSendSms != null) &&
                 (OnClientSendSms.GetInvocationList().Length > 0))
                OnClientSendSms(ClientName, Message);
        }

        public void Client2Server_Connected(string ClientName)
        {
            if ((OnClientConnected != null) &&
                 (OnClientConnected.GetInvocationList().Length > 0))
                OnClientConnected(ClientName);
        }

        public void Client2Server_Disconnected(string ClientName)
        {
            if ((OnClientDisconnected != null) &&
                 (OnClientDisconnected.GetInvocationList().Length > 0))
                OnClientDisconnected(ClientName);
        }

        public bool RegisterClient(string ClientName)
        {
            for (int i = 0; i < _ClientList.Count; i++)
            {
                ClientClass clt = _ClientList[i];
                if (clt.ClientName == ClientName)
                    return false;
            }
            ClientClass Client = new ClientClass();
            Client.ClientName = ClientName;
            _ClientList.Add(Client);
            return true;

        }

        public bool RegisterClient(string __ClientName, OnMessageReceivedDelegate __HostToClientMessage,
                OnSmsReceivedDelegate __HostToClientSms, OnDeliveryReportDelegate __HostToClientDeliveryReport, IsClientConnectedDelegate __HostToClientIsConnected)
        {
            ClientClass Client = null;
            for (int i = 0; i < _ClientList.Count;i++)
            {
                Client = _ClientList[i];
                if (Client.ClientName == __ClientName)
                {
                    try
                    {
                        Client.IsClientConnected();
                        return false;
                    }
                    catch
                    {
                        DisposeClient(Client.ClientName);
                        i--;
                    }
                }
            }
                Client = new ClientClass(__ClientName,
                    __HostToClientMessage, __HostToClientSms,
                    __HostToClientDeliveryReport, __HostToClientIsConnected);
                _ClientList.Add(Client);
            return true;

        }

        public bool DisposeClient(string ClientName)
        {
            if (ClientName == null || ClientName.Trim().Length == 0)
                return false;
            else
            {
                for (int i = 0; i < _ClientList.Count; i++)
                {
                    if (_ClientList[i].ClientName == ClientName)
                    {
                        _ClientList[i].DeliveryReportDelegate = null;
                        _ClientList[i].MessageReceivedDelegate = null;
                        _ClientList[i].SmsReceivedDelegate = null;
                        _ClientList.RemoveAt(i);
                        return true;
                    }
                }
            }
            return false;
        }
        public bool RegisterSmsDelegate(string ClientName, OnSmsReceivedDelegate del)
        {
            for (int i = 0; i < _ClientList.Count; i++)
            {
                ClientClass clt = _ClientList[i];
                if (clt.ClientName == ClientName)
                {
                    clt.SmsReceivedDelegate = del;
                    return true;
                }
            }
            return false;

        }
        public bool RegisterMessageDelegate(string ClientName, OnMessageReceivedDelegate del)
        {
            for (int i = 0; i < _ClientList.Count; i++)
            {
                ClientClass clt = _ClientList[i];
                try
                {
                    if (clt.ClientName == ClientName)
                    {
                        clt.MessageReceivedDelegate = del;
                        return true;
                    }
                }
                catch { }
            }
            return false;

        }

        public bool RegisterDeliveryReportDelegate(string ClientName, OnDeliveryReportDelegate del)
        {
            for (int i = 0; i < _ClientList.Count; i++)
            {
                ClientClass clt = _ClientList[i];
                try
                {
                    if (clt.ClientName == ClientName)
                    {
                        clt.DeliveryReportDelegate = del;
                        return true;
                    }
                }
                catch
                {
                }
            }
            return false;
        }

        public bool IsClientConnected()
        {
            bool returnValue = true;
            for (int i = 0; i < _ClientList.Count;i++ )
            {
                ClientClass clt = _ClientList[i];
                if (clt.IsClientConnected != null)
                {
                    try
                    {
                        clt.IsClientConnected();
                    }
                    catch
                    {
                        DisposeClient(clt.ClientName);
                        i--;
                        returnValue = false;
                    }
                }
            }
            return returnValue;
        }
        public SmsResponseClass Server2Client_SmsReceived(string ClientName, SmsClass Message, bool IncludeClient)
        {
            SmsResponseClass Response = new SmsResponseClass();
            for(int i =0;i<_ClientList.Count;i++)
            {
                ClientClass clt = _ClientList[i];
                try
                {
                    if (IncludeClient == true)
                    {
                        if ((clt.ClientName == ClientName || ClientName == "*") && clt.SmsReceivedDelegate != null)
                        {
                            SmsResponseClass ClientResponse = clt.SmsReceivedDelegate(new SmsClass(Message));
                            if (ClientResponse != null)
                            {
                                for (int j = 0; j < ClientResponse.ResponseMessages.Count; j++)
                                {
                                    ClientResponse.ResponseMessages[j].ClientName = clt.ClientName;
                                    Response.AddResponseSms(ClientResponse.ResponseMessages[j]);
                                }
                            }
                        }
                    }
                    else
                    {
                        if (clt.ClientName != ClientName && clt.SmsReceivedDelegate != null)
                        {
                            SmsResponseClass ClientResponse = clt.SmsReceivedDelegate(new SmsClass(Message));
                            if (ClientResponse != null)
                            {
                                for (int j = 0; j < ClientResponse.ResponseMessages.Count; j++)
                                {
                                    ClientResponse.ResponseMessages[j].ClientName = clt.ClientName;
                                    Response.AddResponseSms(ClientResponse.ResponseMessages[j]);
                                }
                            }

                        }
                    }
                }
                catch
                {
                    //DisposeClient(clt.ClientName);
                    //i--;
                }
            }
            return Response;
        }

        public void Server2Client_DeliveryReportReceived(string ClientName, DeliveryReportClass Report, bool IncludeClient)
        {
            for (int i = 0; i < _ClientList.Count; i++)
            {
                ClientClass clt = _ClientList[i];
                try
                {
                    if (IncludeClient == true)
                    {
                        if ((clt.ClientName == ClientName || ClientName == "*") && clt.DeliveryReportDelegate != null)
                            clt.DeliveryReportDelegate(new DeliveryReportClass(Report));
                    }
                    else
                    {
                        if (clt.ClientName != ClientName && clt.DeliveryReportDelegate != null)
                            clt.DeliveryReportDelegate(new DeliveryReportClass(Report));
                    }
                }
                catch
                {
                }
            }
        }

        public void Server2Client_MessageReceived(string ClientName, string Message, bool IncludeClient)
        {
            for (int i = 0; i < _ClientList.Count; i++)
            {
                ClientClass clt = _ClientList[i];
                try
                {
                    if (IncludeClient == true)
                    {
                        if ((clt.ClientName == ClientName || ClientName == "*") && clt.MessageReceivedDelegate != null)
                            clt.MessageReceivedDelegate(Message);
                    }
                    else
                    {
                        if (clt.ClientName != ClientName && clt.MessageReceivedDelegate != null)
                            clt.MessageReceivedDelegate(Message);
                    }
                }
                catch
                {
                }
            }
        }

        public class ClientClass
        {
            private string _ClientName = "";
            private OnMessageReceivedDelegate _ServerToClientMessage = null;
            private OnSmsReceivedDelegate _ServerToClientSms = null;
            private OnDeliveryReportDelegate _ServerToClientDeliveryReport = null;
            private IsClientConnectedDelegate _ServerToClientIsConnected = null;
            public ClientClass() { }
            public ClientClass(string __ClientName, OnMessageReceivedDelegate __HostToClientMessage,
                OnSmsReceivedDelegate __HostToClientSms, OnDeliveryReportDelegate __HostToClientDeliveryReport, IsClientConnectedDelegate __HostToClientIsConnected)
            {
                _ClientName = __ClientName;
                _ServerToClientMessage = __HostToClientMessage;
                _ServerToClientDeliveryReport = __HostToClientDeliveryReport;
                _ServerToClientSms = __HostToClientSms;
                _ServerToClientIsConnected = __HostToClientIsConnected;
            }

            public string ClientName
            {
                get { return _ClientName; }
                set { _ClientName = value; }
            }

            public OnSmsReceivedDelegate SmsReceivedDelegate
            {
                get { return _ServerToClientSms; }
                set { _ServerToClientSms = value; }
            }
            public OnMessageReceivedDelegate MessageReceivedDelegate
            {
                get { return _ServerToClientMessage; }
                set { _ServerToClientMessage = value; }
            }

            public OnDeliveryReportDelegate DeliveryReportDelegate
            {
                get { return _ServerToClientDeliveryReport; }
                set { _ServerToClientDeliveryReport = value; }
            }

            public IsClientConnectedDelegate IsClientConnected
            {
                get { return _ServerToClientIsConnected; }
                set { _ServerToClientIsConnected = value; }
            }
        }

    }



    /// <summary>
    /// This CallbackSink object will be 'anchored' on the client and is used as the target for a callback
    /// given to the server.
    /// </summary>
    public class CallbackSinkClass : MarshalByRefObject
    {
        public event OnMessageReceivedDelegate OnMessageReceived;
        public event OnSmsReceivedDelegate OnSmsReceived;
        public event OnDeliveryReportDelegate OnDeliveryReportReceived;
        public event IsClientConnectedDelegate IsClientConnected;
        public CallbackSinkClass()
        { }

        [OneWay]
        public void HandleMessageReceived(string Message)
        {
            if (OnMessageReceived != null)
                OnMessageReceived(Message);
        }

        public SmsResponseClass HandleSmsReceived(SmsClass Message)
        {
            if (OnSmsReceived != null)
                return OnSmsReceived(Message);
            return null;
        }

        public void HandleDeliveryReportReceived(DeliveryReportClass Report)
        {
            if (OnDeliveryReportReceived != null)
                OnDeliveryReportReceived(Report);
        }

        public bool HandleIsClientConnected()
        {
            if (IsClientConnected != null)
                return IsClientConnected();
            return false;
        }
    }

    public class SmsServiceClass
    {
        private string _SubscriberName = "";
        private IpcChannel ipcChannel = null;
        private SmsPublishClass Publisher = null;
        private CallbackSinkClass CallBackSink = null;
        internal event OnMessageReceivedDelegate OnMessageReceived;
        public event OnSmsReceivedDelegate OnSmsReceived;
        public event OnDeliveryReportDelegate OnDeliveryReportReceived;
        public bool IsConnected
        {
            get
            {
                if (Publisher != null)
                    return Publisher.IsConnected;
                else
                    return false;
            }
        }

        
        public string SubscriberName
        {
            get { return _SubscriberName; }
        }
        public SmsServiceClass(string SubscriberName)
        {
            if (SubscriberName != null && SubscriberName.Trim().Length != 0)
            {
                Process agent = null;
                string applicationpath = null;
                string workingdirectory = null;
                RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\MSR India\SmsDesktopAgent");

                if (key != null)
                {
                    applicationpath = (string)key.GetValue("applicationpath", string.Empty);
                    workingdirectory = (string)key.GetValue("workingdirectory", string.Empty);
                }
                if (applicationpath != null)
                {
                    Process[] Plist = Process.GetProcesses();
                    bool found = false;
                    foreach (Process p in Plist)
                    {
                        if (p.ProcessName == "SmsDesktopAgent")
                        {
                            found = true;
                            break;
                        }
                    }
                    if (found == false)
                    {
                        agent = new Process();
                        agent.StartInfo.FileName = applicationpath;
                        agent.StartInfo.WorkingDirectory = workingdirectory;
                        agent.Start();
                        agent.WaitForInputIdle();
                        agent.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
                        Application.DoEvents();
                        Thread.Sleep(5000);
                    }
                }
                _SubscriberName = SubscriberName;

                BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
                serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
                BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
                System.Collections.Hashtable properties = new System.Collections.Hashtable();
                properties["name"] = "MSRI_Sms_Server";
                properties["portName"] = SubscriberName;
                properties["timeout"] = "-1";
                properties["socketCacheTimeout"] = "-1";
                properties["connectionTimeout"] = "-1";
                properties["exclusiveAddressUse"] = false;
                properties["typeFilterLevel"] = "Full";
                ipcChannel = new IpcChannel(properties, clientProv, serverProv);
                ChannelServices.RegisterChannel(ipcChannel, false);
                Publisher = (SmsPublishClass)Activator.GetObject(typeof(SmsPublishClass),
                    "ipc://MSRI_Sms_Server/MSRI_Sms_Server.rem");
                if (Publisher == null)
                {
                    if (ipcChannel != null)
                        ChannelServices.UnregisterChannel(ipcChannel);
                    throw new Exception("Error:Failed to communicate with Sms Server Desktop Agent");
                }
                CallBackSink = new CallbackSinkClass();
                CallBackSink.OnDeliveryReportReceived += new OnDeliveryReportDelegate(CallBackSink_OnDeliveryReportReceived);
                CallBackSink.OnMessageReceived += new OnMessageReceivedDelegate(CallBackSink_OnMessageReceived);
                CallBackSink.OnSmsReceived += new OnSmsReceivedDelegate(CallBackSink_OnSmsReceived);
                CallBackSink.IsClientConnected += new IsClientConnectedDelegate(CallBackSink_IsClientConnected);
                try
                {
                    if (Publisher.RegisterClient(_SubscriberName, CallBackSink.HandleMessageReceived,
                        CallBackSink.HandleSmsReceived, CallBackSink.HandleDeliveryReportReceived, CallBackSink.HandleIsClientConnected) == false)
                        throw new Exception("Error:Unable to register service name");
                    Publisher.Client2Server_Connected(SubscriberName);
                }
                catch
                {
                    CallBackSink = null;
                    if (ipcChannel != null)
                        ChannelServices.UnregisterChannel(ipcChannel);
                    Publisher = null;
                    throw new Exception("Error:Please restart the Sms Desktop Agent or refresh the Client List");
                }
            }
            else
            {
                if (ipcChannel != null)
                    ChannelServices.UnregisterChannel(ipcChannel);
                throw new Exception("Error:Invalid SubscriberName");
            }
        }

        bool CallBackSink_IsClientConnected()
        {
            return true;
        }

        SmsResponseClass CallBackSink_OnSmsReceived(SmsClass SmsMessage)
        {
            if (OnSmsReceived != null)
                return OnSmsReceived(SmsMessage);
            return null; 
        }

        void CallBackSink_OnMessageReceived(string Message)
        {
            if (OnMessageReceived != null)
                OnMessageReceived(Message);
        }

        void CallBackSink_OnDeliveryReportReceived(DeliveryReportClass DeliveryReport)
        {
            if (OnDeliveryReportReceived != null)
                OnDeliveryReportReceived(DeliveryReport);
        }

        public void SendSms(SmsClass Message)
        {
            if (Publisher != null)
                Publisher.Client2Server_SendSms(_SubscriberName, new SmsClass(Message));
        }
        internal void SendMessage(string Message)
        {
            if (Publisher != null)
                Publisher.Client2Server_SendMessage(_SubscriberName, Message);
        }

        ~SmsServiceClass()
        {
            try
            {
                if (Publisher != null)
                {
                    Publisher.DisposeClient(_SubscriberName);
                    Publisher.Client2Server_Disconnected(_SubscriberName);
                }
                if (ipcChannel != null)
                    ChannelServices.UnregisterChannel(ipcChannel);
            }
            catch 
            {
                
            }
        }

    }



}
